// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/sysctl.h>
#include <linux/types.h>
#include <linux/minmax.h>
#include <linux/mm.h>

#include <memory/mmap_rnd_mask.h>

unsigned long mmap_rnd_mask __read_mostly = ~0UL;
unsigned long mmap_rnd_invert_mask;
unsigned long *mmap_rnd_invert_mask_p = &mmap_rnd_invert_mask;

int proc_mmap_rnd_mask(struct ctl_table *table, int write,
		       void *buffer, size_t *lenp, loff_t *ppos)
{
	int err;
	int max_bits = min(mmap_rnd_bits_max + PAGE_SHIFT, BITS_PER_LONG);

	err = proc_do_large_bitmap(table, write, buffer, lenp, ppos);
	if (err)
		goto error;

	if (write) {
		if (mmap_rnd_invert_mask & ~GENMASK(max_bits - 1, 0)) {
			err = -EINVAL;
			goto error;
		}
		mmap_rnd_mask = ~mmap_rnd_invert_mask;
		pr_info("mmap_rnd_mask is set to 0x%lx\n", mmap_rnd_mask);
	}
	return 0;

error:
	if (write)
		mmap_rnd_invert_mask = ~mmap_rnd_mask;
	return err;
}

static struct ctl_table euleros_mmap_sysctls[] = {
	{
		.procname	= "mmap_rnd_mask",
		.data		= &mmap_rnd_invert_mask_p,
		.maxlen		= BITS_PER_LONG,
		.mode		= 0600,
		.proc_handler	= proc_mmap_rnd_mask,
	},
	{}
};

static int __init euleros_mmap_sysctl_init(void)
{
	register_sysctl_init("vm", euleros_mmap_sysctls);
	return 0;
}
late_initcall(euleros_mmap_sysctl_init);
